package com.codebattery.config;


import com.codebattery.domain.entity.Dict;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.util.JSONTokener;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;

/**
 * @Description: 字典aop类 (用于翻译字典数据)
 * @Date: 2019-3-17 21:50
 * @Version: 1.0
 */
@Aspect
@Component
public class DataDictAspect {

    @Autowired
    private ValueOperations valueOperations;

    // 定义切点Pointcut 拦截所有对服务器的请求
    @Pointcut("execution( * com.codebattery.controller.*.*(..))")
    public void excudeService() {

    }

    /**
     * 这是触发 excudeService 的时候会执行的
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        Object result = pjp.proceed();


        if(Collection.class.isAssignableFrom(result.getClass())) {
            JSONArray jsonArray = (JSONArray)JSONArray.fromObject(result);
            if(!jsonArray.isEmpty()){
                if (Collection.class.isAssignableFrom(result.getClass())) {
                    Collection<Object> collection = (Collection<Object>) result;
                    Object[] objects = collection.toArray();

                    for(int i=0; i<jsonArray.size(); i++){
                        JSONObject jsonObject = jsonArray.getJSONObject(i);
                        traverseJSONObject(objects[i], jsonObject);
                    }
                }
            }
        } else {
            traverseJSONObject(result, (JSONObject)JSONObject.fromObject(result));
        }


        return result;
    }

    public void traverseJSONObject(Object result, JSONObject json){
        Iterator<String> keys=json.keys();
        JSONObject jo=null;
        Object o;
        String key;
        while(keys.hasNext()){
            key=keys.next();
            o=json.get(key);


            Object oValue = getValue(result, key);

            if(oValue == null) {
                continue;
            }

            if(o instanceof JSONArray) {
                JSONArray jsonArray = (JSONArray)o;
                if(!jsonArray.isEmpty()){

                    if (Collection.class.isAssignableFrom(oValue.getClass())) {
                        Collection<Object> collection = (Collection<Object>) oValue;
                        Object[] objects = collection.toArray();

                        for(int i=0; i<jsonArray.size(); i++){
                            JSONObject jsonObject = jsonArray.getJSONObject(i);
                            traverseJSONObject(objects[i], jsonObject);
                        }
                    }
                }
            } else if(o instanceof JSONObject ){
                jo=(JSONObject)o;
                if(jo.keySet().size()>0){
                    traverseJSONObject(oValue, jo);
                }
            }
        }
    }

    private boolean isKeyInField(Field [] fields, String key){
        boolean result = false;
        for(Field f : fields){
            if(f.getName().equals(key)){
                result = true;
            }
        }
        return result;
    }

    private Object getValue(Object obj, String filedName) {

        Object fieldValue = null;

        try {
            Field f = ReflectionUtils.findField(obj.getClass(), filedName);

            if(f==null) {
                return fieldValue;
            }

            f.setAccessible(true);
            fieldValue = f.get(obj);

            DataDict dictannotation = f.getAnnotation(DataDict.class);
            if (dictannotation != null) {
                String code = dictannotation.value();
                Field valueField = ReflectionUtils.findField(obj.getClass(), code);
                ReflectionUtils.makeAccessible(valueField);
                final Object value = valueField.get(obj);
                Object redisValue = valueOperations.get("Dict:" + value);
                if(redisValue != null){
                    f.set(obj, ((Dict)redisValue).getText());
                }
            }

        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return fieldValue;
    }
}
